//
//  YBNetworking.m
//  YanzhouCloud
//
//  Created by Cocoa on 2019/7/2.
//  Copyright © 2019 yibai. All rights reserved.
//

#import "YBNetworking.h"
#import <AFNetworking.h>
#import "TFCLogger.h"

NSString *const Rest_Path = @"REST_PATH";
NSString *const Rest_Method = @"REST_METHOD";
NSString *const Rest_Param = @"REST_PARAM";
NSString *const Rest_Model = @"REST_MODEL";
NSString *const Rest_MultiMediaBlock = @"Rest_MultiMediaBlock";


@interface YBNetworking ()

@end

@implementation YBNetworking
{
    AFHTTPSessionManager *_manager;
    NSMutableDictionary *_HTTPHeaderFields;
}
- (instancetype)initWithBaseURL:(NSURL *)baseURL {
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    return [self initWithBaseURL:baseURL configuration:configuration];
}
- (instancetype)initWithBaseURL:(NSURL *)baseURL configuration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (self) {
        _manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL sessionConfiguration:configuration];
        NSMutableSet *acceptableContentTypeSet = [NSMutableSet setWithSet:_manager.responseSerializer.acceptableContentTypes];
        [acceptableContentTypeSet addObject:@"text/html"];
        [acceptableContentTypeSet addObject:@"text/plain"];
        _manager.responseSerializer.acceptableContentTypes = acceptableContentTypeSet;
        _manager.requestSerializer.timeoutInterval = 60.f;
//        _manager.requestSerializer = [AFJSONRequestSerializer serializer];
        _HTTPHeaderFields = [NSMutableDictionary dictionary];
//        [self setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    }
    return self;
}

- (void)setValue:(id)value forHTTPHeaderField:(nonnull NSString *)field {
    [_HTTPHeaderFields setObject:value forKey:field];
}
- (void)removeValueForHTTPHeaderField:(nonnull NSString *)field {
    [_HTTPHeaderFields removeObjectForKey:field];
}


#pragma mark - public
- (RACSignal *(^)(NSString *, NSString *, NSDictionary *))call {
    static RACSignal *(^sc)(NSString *, NSString *, NSDictionary *);
//    if (sc == nil) {
        @weakify(self);
        sc = ^(NSString *method, NSString *path, NSDictionary *param) {
            @strongify(self);
            return [self sendRequest:@{Rest_Method: method,
                                       Rest_Path: path,
                                       Rest_Param: param ?: @{}
                                       }];
        };
//    }
    return sc;
}
- (RACSignal *(^)(NSString *, NSString *, NSDictionary *))download {
    static RACSignal *(^dl)(NSString *, NSString *, NSDictionary *);
    
    return dl;
}

- (RACSignal *)sendRequest:(NSDictionary *)reqInfo {
    NSURLRequest *req = [self _parseRequest:reqInfo];
    RACSignal *reqSig = [self _call:req _reqInfo:reqInfo];
    
    return [[reqSig flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable res) {
        return [self _responseCheck:res request:reqInfo];
    }] map:^id _Nullable(id  _Nullable value) {
        NSMutableDictionary *res = [value mutableCopy];
        //        [res removeObjectForKey:@""]
        return res;
    }] ;
}
- (RACSignal *)download:(NSURL *)url destination:(NSURL *)fileURL {
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    return [self _download:req destination:fileURL];
}

#pragma mark - private
- (RACSignal *)_call:(NSURLRequest *)req _reqInfo:(NSDictionary *)reqInfo {
    @weakify(self);
    return [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        @strongify(self);
        NSURLSessionDataTask *task = [self->_manager dataTaskWithRequest:req uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            if (!error) {
                if (!responseObject){
                    error = [NSError errorWithDesc:@"未知错误！" code:10000];
                    [subscriber sendError:error];
                    derror(@"[REST ERROR] - %@, request: %@", error, reqInfo);
                }else{
                    [subscriber sendNext:responseObject];
                    [subscriber sendCompleted];
                }
                
            } else {
                [subscriber sendError:error];
                derror(@"[REST ERROR] - %@, request: %@", error, reqInfo);
            }
        }];
        [task resume];
        
        return [RACDisposable disposableWithBlock:^{
            [task cancel];
        }];
    }] doError:^(NSError * _Nonnull error) {
        derror(@"send request error - %@", error);
    }];
}

- (RACSignal *)_download:(NSURLRequest *)req destination:(NSURL *)fileURL {
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        @strongify(self);
        RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
        
        NSURLSessionDownloadTask *task = [self->_manager downloadTaskWithRequest:req progress:^(NSProgress * _Nonnull downloadProgress) {
            [subscriber sendNext:@(downloadProgress.fractionCompleted)];
        } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
            return fileURL;
        } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
            if (!error) {
                [subscriber sendNext:filePath];
                [subscriber sendCompleted];
            } else {
                [subscriber sendError:error];
            }
            [compoundDisposable dispose];
        }];
        [task resume];
        
        return [RACDisposable disposableWithBlock:^{
            [compoundDisposable dispose];
            [task cancel];
        }];
    }];
}

- (NSURLRequest *)_parseRequest:(NSDictionary *)info {
    NSParameterAssert(info[Rest_Path] && info[Rest_Method]);
    
    NSString *path;
    if (_manager.baseURL != nil) {
        path = [[_manager.baseURL absoluteString] stringByAppendingPathComponent:info[Rest_Path]];
    } else {
        path = info[Rest_Path];
    }
    
    NSError *error = nil;
    //    NSMutableURLRequest *req = [_manager.requestSerializer requestWithMethod:info[Rest_Method] URLString:path parameters:info[Rest_Param] error:&error];
    //    _manager.requestSerializer = [AFJSONRequestSerializer serializer];
    NSMutableURLRequest *req = nil;
    if (info[Rest_Param][Rest_MultiMediaBlock]) {
        req = [_manager.requestSerializer multipartFormRequestWithMethod:info[Rest_Method] URLString:path parameters:info[Rest_Param] constructingBodyWithBlock:info[Rest_Param][Rest_MultiMediaBlock] error:&error];
    }else{
        req = [_manager.requestSerializer requestWithMethod:info[Rest_Method] URLString:path parameters:info[Rest_Param] error:&error];
    }
    if (_HTTPHeaderFields.count > 0) {
        for (NSString *key in _HTTPHeaderFields.allKeys) {
            [req setValue:_HTTPHeaderFields[key] forHTTPHeaderField:key];
        }
    }
    
    if (error != nil) {
        NSString *reason = [NSString stringWithFormat:@"Rest parseRequest failed with %@", error];
        @throw [NSException exceptionWithName:@"RequestSerialize" reason:reason userInfo:nil];
    }
    
    return req;
}

- (RACSignal *)_responseCheck:(id)res request:(NSDictionary *)req {
    
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(ybNetworking:didReceiveDatas:)]) {
        [self.delegate ybNetworking:self didReceiveDatas:res];
    }
    
    return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
        int code = [res[@"code"] intValue];
        
        if (code == 1) { //  成功
            [subscriber sendNext:res];
            [subscriber sendCompleted];
            dverb(@"request:\n%@\n[REST RESP] : \n%@", req, [res description]);
        } else {
            
            derror(@"request : %@ get error response: %@", req, res);
            [subscriber sendError:[NSError errorWithDomain:@"server" code:code userInfo:@{@"serverResponse": res,NSLocalizedDescriptionKey:res[@"msg"]}]];
            
        }
        return nil;
    }];
}

@end
